package ldh.im.fxgui.service;

import javafx.concurrent.Task;
import ldh.im.ImConfig;
import ldh.im.dto.base.OkListResp;
import ldh.im.dto.business.message.MessageObject;
import ldh.im.dto.business.message.MessageObjectsReq;
import ldh.im.dto.enums.MessageType;
import ldh.im.fxbase.dao.ImMessageDao;
import ldh.im.fxbase.dao.ImMessageSendDao;
import ldh.im.fxbase.dao.ImSessionDao;
import ldh.im.fxbase.data.pojo.*;
import ldh.im.fxbase.data.pojo.status.*;
import ldh.im.fxbase.richtext.*;
import ldh.im.fxbase.richtext.item.EmojiTextItem;
import ldh.im.fxbase.richtext.item.FileTextItem;
import ldh.im.fxbase.richtext.item.ImageTextItem;
import ldh.im.fxbase.rpc.service.RpcMessageService;
import ldh.im.fxbase.service.FileService;
import ldh.im.fxbase.util.*;
import ldh.im.fxbase.util.MessageUtil;
import ldh.im.fxgui.util.UiUtil;
import ldh.im.util.ConfigUtil;
import ldh.im.util.DateUtil;
import ldh.im.util.Sets;
import ldh.rpc.cache.CacheService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.sql.SQLException;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 发送消息
 */
public class MessageSendService {

    private static final Logger LOGGER = LoggerFactory.getLogger(MessageSendService.class);

    private ImMessageDao imMessageDao = BeanFactory.getInstance().getBean(ImMessageDao.class);
    private ImMessageSendDao imMessageSendDao = BeanFactory.getInstance().getBean(ImMessageSendDao.class);
    private ImSessionDao imSessionDao = BeanFactory.getInstance().getBean(ImSessionDao.class);
    private FileService fileService = BeanFactory.getInstance().getBean(FileService.class);

    private RpcMessageService rpcMessageService = RpcUtil.getRpcBootstrap().getRpcConfig().getClientBean(RpcMessageService.class);

    public Task sendMessage(ImSession imSession, List<ImMessage> imMessages) {
        Task<OkListResp> sendMessageTask = sendMessage(Sets.asSet(imSession), imMessages);
        return sendMessageTask;
    }

    public Task sendMessage(Set<ImSession> imSessions, List<ImMessage> imMessages) {
        Task<OkListResp> sendMessageTask = new Task<OkListResp>() {

            @Override
            protected OkListResp call() throws Exception {
                // step 1  本地保存数据
                saveMessages(imSessions, imMessages);
                updateMessage("保存数据成功");
                updateProgress(30, 100);

                //  step 2 数据发送到服务器
                OkListResp okResp = sendMessageToServer(imMessages);
                updateMessage("数据发送成功");
                updateProgress(70, 100);

                // step 3 本地业务处理
                doSendSuccess(okResp, imMessages);
                updateMessage("数据处理成功");
                updateProgress(100, 100);
                return okResp;
            }
        };
        ThreadPoolUtil.submitTask(sendMessageTask);
        return sendMessageTask;
    }

    /**
     * 只发送消息，不进行本地处理
     * @param messages
     * @throws Exception
     */
    public void sendMessages(List<ImMessage> messages) throws Exception {
        OkListResp okListResp = sendMessageToServer(messages);
        doSendSuccess(okListResp, messages);
    }

    /**
     * 构建发送消息对象
     *
     * @param imSession
     * @param msg
     * @param refMessage
     * @return
     */
    public List<ImMessage> buildMessages(ImSession imSession, String msg, ImMessage refMessage) {
        if (msg.equals("")) return new ArrayList<>();

        List<Object> messages = ImRichTextUtil.splitMessage(msg);

        List<ImMessage> imMessages = new ArrayList<>();
        for(Object obj : messages) {
            if (obj instanceof String) {
                ImMessage textMessage = null;
                String content = obj.toString();
                if (RegexUtil.isUrl(content)) {
                    textMessage = buildMessage(imSession, content, MessageType.Url, refMessage);
                } else if(!RegexUtil.isRichText(content)) {
                    textMessage = buildMessage(imSession, content, MessageType.Text, refMessage);
                } else {
                    textMessage = buildMessage(imSession, content, MessageType.RichText, refMessage);
                }
                imMessages.add(textMessage);
            } else {
                TextItem textItem = (TextItem) obj;
                if (textItem instanceof ImageTextItem) {
                    ImMessage textMessage = buildMessage(imSession, textItem.getData(), MessageType.Image, refMessage);
                    imMessages.add(textMessage);
                } else if (textItem instanceof FileTextItem) {
                    ImMessage textMessage = buildMessage(imSession, textItem.getData(), MessageType.File, refMessage);
                    imMessages.add(textMessage);
                } else if (textItem instanceof EmojiTextItem) {
                    ImMessage textMessage = buildMessage(imSession, textItem.getData(), MessageType.RichText, refMessage);
                    imMessages.add(textMessage);
                } else {
                    throw new RuntimeException("不支持这种类型:" + textItem.getTextItemType());
                }

            }
        }

        return imMessages;
    }

    /**
     * 构建单个消息
     * @param imSession
     * @param content
     * @param messageType
     * @param refMessage
     * @return
     */
    public ImMessage buildMessage(ImSession imSession, String content, MessageType messageType, ImMessage refMessage) {
//        String imageRelativePath = content.replace(ConfigUtil.getRoot(), "");
        ImMessage message = new ImMessage();
        message.setFromImUser(UiUtil.getLoginImUser());
        message.setClientId(RpcUtil.getRpcBootstrap().getRpcConfig().getLocalSeqCreator().create());
        message.setGroupCode(imSession.getGroupCode());
        message.setContent(content);
        message.setMessageType(messageType);
        message.setCurrentUserId(UiUtil.getLoginImUser().getUserId());
        message.setStatus(ImMessageStatus.created);
        message.setActionStatus(ImMessageActionStatus.none);
        message.setImSession(imSession);
        message.setServerReceiveTime(new Date());
        if (imSession.isP2p()) {
            message.setToImUser(initToUser(imSession));
        } else {
            message.setGroupCode(imSession.getGroupCode());
            ImGroup imGroup = ImCacheFactory.getInstance().getImGroup(imSession.getCurrentUserId(), imSession.getGroupCode());
            imSession.setImGroup(imGroup);
            Set<ImMessageSend> messageSends = imGroup.getGroupUserSet().stream().map(gu->buildMessageSend(imGroup, gu)).collect(Collectors.toSet());
            message.setMessageSendSet(messageSends);
        }

        if (messageType.isFile()) {
            message.setFileStatus(ImMessageFileStatus.created);

            File file = new File(FileUtil.getFilePath(message));
            String root = ConfigUtil.getRoot();
            String fileUrl = file.getPath().replace(root, ""); // 使用相对路径
            MessageExt messageExt = new MessageExt();
            messageExt.setFileName(file.getName());
            messageExt.setOriginalName(file.getName());
            messageExt.setSize(FileUtil.getFileSize(file));
            messageExt.setRemote(false);
            messageExt.setFileUrl(fileUrl);
            message.setMessageExt(messageExt);

            String md5 = MessageUtil.getFileSha512(file);
            messageExt.setMd5(md5);

            if (messageType == MessageType.Image) {
                int[] size = FileUtil.getImageSize(file);
                messageExt.setImageSize(size);
            }

            message.initExt();
            message.setContent(fileUrl);
        }

        if (refMessage != null) {
            message.setRefMessageIds(Arrays.asList(refMessage).stream().map(rm->rm.getServerId()).collect(Collectors.joining(",")));
            message.setRefType(ImMessageRefType.ref);
            message.setRefMessages(Arrays.asList(refMessage));
        }

        String latelyMessage = MessageUtil.buildLastedMessage(messageType, message.getContent());
        imSession.setLatelyMessage(latelyMessage);
        imSession.setUpdateTime(new Date());

        return message;
    }

    private ImMessageSend buildMessageSend(ImGroup group, ImGroupUser groupUser) {
        ImMessageSend messageSend = new ImMessageSend();
        messageSend.setUserId(groupUser.getUserId());
        messageSend.setActionStatus(ImMessageActionStatus.none);
        messageSend.setFileStatus(ImMessageFileStatus.none);
        messageSend.setStatus(ImMessageStatus.none);
        if (groupUser.getUserId().equals(UiUtil.getLoginImUser().getUserId())) {
            messageSend.setStatus(ImMessageStatus.created);
        }
        return messageSend;
    }

    private ImUser initToUser(ImSession imSession) {
        if (imSession.isP2p()) {
            ImUser imUser = imSession.getToImUser();
            if (imUser == null) {
                imUser = ImCacheFactory.getInstance().getUser(imSession.getToUserId());
            }
            return imUser;
        }
        throw new RuntimeException("不是p2p会话");
    }

    private void saveMessages(Set<ImSession> imSessions, List<ImMessage> imMessages) throws SQLException {
        imSessionDao.batchUpdates(imSessions.stream().collect(Collectors.toList()));
        imMessageDao.saveMessages(imMessages);
        for (ImMessage imMessage : imMessages) {
            if (!imMessage.isGroup()) continue;
            imMessage.getMessageSendSet().forEach(ms->ms.setMessageId(imMessage.getId()));
            imMessageSendDao.insertMessageSends(imMessage.getMessageSendSet().stream().collect(Collectors.toList()));
        }
    }

    private OkListResp sendMessageToServer(List<ImMessage> imMessages) {
        List<MessageObject> messageObjects = imMessages.stream().map(m->MessageUtil.toMessageObject(m)).collect(Collectors.toList());
        MessageObjectsReq messageObjectsReq = new MessageObjectsReq();
        messageObjectsReq.setMessageObjects(messageObjects);
        OkListResp okResp = rpcMessageService.sendMessages(messageObjectsReq);
        return okResp;
    }

    private void doSendSuccess(OkListResp okListResp, List<ImMessage> messages) throws Exception {
        CacheService cacheService = RpcUtil.getRpcBootstrap().getRpcConfig().getCacheService();
        String userId = (String) cacheService.getCache(ImConfig.LOGIN_USER_ID);
        Date serverDateTime = DateUtil.toDate(okListResp.getSuccessDataTime());
        Map<String, ImMessage> clientIdMessageMap = messages.stream().collect(Collectors.toMap(ImMessage::getClientId, Function.identity()));

        Set<ImSession> updateSessions = new HashSet<>();
        for (String serverInfo : okListResp.getLocalSeqSet()) {
            String[] ids = serverInfo.split(ImConfig.MESSAGE_SPLIT);
            String serverId = ids[1];
            String clientId = ids[0];
            String sessionId = ids[2];
            ImMessage imMessage = clientIdMessageMap.get(clientId);
            imMessage.setServerId(serverId);
            imMessage.setStatus(ImMessageStatus.sended);
            imMessage.setServerReceiveTime(serverDateTime);
            imMessage.setUpdateDateTime(new Date());

            ImSession session = imMessage.getImSession();
            if (session == null) {
                if (imMessage.getGroupCode() != null) {
                    session = imSessionDao.getByGroupCodeAndUserId(imMessage.getGroupCode(), userId);
                } else {
                    session = imSessionDao.getByUserId(userId, imMessage.getFromUserId(), imMessage.getToUserId());
                }
            }
            if (session.getServerId() == null) {
                session.setServerId(sessionId);
                session.setUpdateTime(new Date());
                updateSessions.add(session);
            }
            if (session.getStatus() == ImSessionStatus.created) {
                session.setStatus(ImSessionStatus.enable);
                session.setUpdateTime(new Date());
                updateSessions.add(session);
            }
        }

        imMessageDao.batchChangeMessageStatus(messages);
        imSessionDao.batchUpdates(updateSessions.stream().collect(Collectors.toList()));
        for (ImMessage imMessage : messages) {
            if(!imMessage.isGroup()) continue;
            if (imMessage.getMessageSendSet() != null) continue;
            List<ImMessageSend> messageSendList = imMessageSendDao.getByMessageId(imMessage.getId());
            imMessage.setMessageSendSet(messageSendList.stream().collect(Collectors.toSet()));
        }
        List<ImMessageSend> messageSends = messages.stream().filter(m->m.isGroup()).flatMap(m->m.getMessageSendSet().stream()).filter(ms->ms.getUserId().equals(userId))
                .map(ms->{
                    ms.setActionStatus(ImMessageActionStatus.readed);
                    ms.setUpdateTime(new Date());
                    return ms;
                }).collect(Collectors.toList());

        if (messageSends.size() > 0) {
            imMessageSendDao.batchChangeMessageSendActionStatus(userId, messageSends);
        }
        FxThreadUtil.runLater(()-> {
            UiUtil.uiUpdateMessages(messages);
        });

        for(ImMessage imMessage : messages) {
            if (imMessage.getMessageType().isFile()) {
                fileService.saveFile(userId, imMessage);

                RpcUtil.getImService().sendFile(imMessage, new DefaultFileProgressListener());
            }
        }
    }

}
